package archer.framework.client.servlet;


import archer.framework.protocol.ArcherProtocolModule;
import archer.framework.utils.HttpUtils;
import archer.framework.utils.RemoteInvokeUtils;
import archer.framework.utils.SignatureUtils;
import archer.framework.utils.ValidateUtils;
import jodd.http.HttpBrowser;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * 远程接口调用Servlet
 *
 * @author christ
 * @date 2015/8/11
 */
public class RemoteInvokeServlet extends HttpServlet {

    private static Logger logger = LoggerFactory.getLogger(RemoteInvokeServlet.class);

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        invoke(req, resp);
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        invoke(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        invoke(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        invoke(req, resp);
    }

    protected void invoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        RemoteInvokeUtils.log(req);

        HttpResponse httpResponse = innerInvoke(req, resp);

        // 为结果设置返回状态
        resp.setStatus(httpResponse.statusCode());

        if (200 == httpResponse.statusCode()) {

            // 回写结果
            resp.getWriter().println(httpResponse.bodyText());
            resp.flushBuffer();
            return;
        }
    }

    private HttpResponse innerInvoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 格式化请求
        RemoteInvokeUtils.format(req, resp);

        String url = req.getRequestURI().substring(req.getContextPath().length());

        // 获取接口调用请求的url
        HttpRequest request = new HttpRequest().method(req.getMethod().toUpperCase())
                .set(RemoteInvokeUtils.decodeUrl(RemoteInvokeUtils.getUrl(req), RemoteInvokeUtils.getConfig(url).getMask(), RemoteInvokeUtils.getConfig(url).getVersion())).charset("UTF-8");

        // ua设置
        request.header("User-Agent", ArcherProtocolModule.userAgent);

        // 设置连接的timeout属性
        request.timeout(RemoteInvokeUtils.getConfig(url).getTimeout());

        // 为接口调用请求添加apikey参数
        RemoteInvokeUtils.addApikey(request, url);

        // 为接口调用请求添加token
        RemoteInvokeUtils.addToken(request, req.getCookies());

        // 为接口调用请求添加界面参数
        RemoteInvokeUtils.addParam(request, req, null);

        // 签名处理
        if ("POST".equals(req.getMethod().toUpperCase())) {
            String sign = SignatureUtils.genSignature(HttpUtils.asParameterMap(request.form()), RemoteInvokeUtils.getConfig(url).getApisecret(), ArcherProtocolModule.signatureField);
            if (ValidateUtils.isNotEmpty(sign)) {
                request.form(ArcherProtocolModule.signatureField, sign);
            }
        } else {
            String sign = SignatureUtils.genSignature(HttpUtils.asParameterMap(request.query()), RemoteInvokeUtils.getConfig(url).getApisecret(), ArcherProtocolModule.signatureField);
            if (ValidateUtils.isNotEmpty(sign)) {
                request.query(ArcherProtocolModule.signatureField, sign);
            }
        }

        HttpBrowser browser = new HttpBrowser();
        try {
            // 发起请求
            browser.sendRequest(request);
        } catch (Exception e) {
            logger.error("调用接口：" + url + " 出错", e);

            resp.setStatus(500);
            throw new ServletException("服务器内部错误");
        }

        int statusCode = browser.getHttpResponse().statusCode();

        // 为结果设置返回状态
        resp.setStatus(statusCode);

        if (200 == statusCode) {

            // 如果请求的是登录接口，则将接口返回的token写入cookie
            if (RemoteInvokeUtils.needCookieToken(url)) {
                RemoteInvokeUtils.cookieToken(browser.getPage(), resp);
            }

        }
        return browser.getHttpResponse();
    }
}
